<?php
/*
 *      Copyright 2010 Rob McFadzean <rob.mcfadzean@gmail.com>
 *      
 *      Permission is hereby granted, free of charge, to any person obtaining a copy
 *      of this software and associated documentation files (the "Software"), to deal
 *      in the Software without restriction, including without limitation the rights
 *      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *      copies of the Software, and to permit persons to whom the Software is
 *      furnished to do so, subject to the following conditions:
 *      
 *      The above copyright notice and this permission notice shall be included in
 *      all copies or substantial portions of the Software.
 *      
 *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *      THE SOFTWARE.
 *
 */  
 
class SteamAPIException extends Exception { }
class SteamAPI {
	
	private $customURL;
	private $steamID64;
	private $gameList;
    private $steamID = '';
    
    private $cacheDIR;
    private $gameCacheTime = 3600;
    private $profileCacheTime = 600;
	
	function version() {
		return (float) '0.2';
	}
    
    /**
	 *  Sets the $steamID64, CustomURL, or SteamID then retrieves the profile.
	 * @param string $id
	 * */
	function __construct($id) {
        $id = str_replace(' ', '', stripslashes(strtolower(htmlspecialchars($id))));
        $this->cacheDIR = __DIR__ . "/cache";        
        $strExplode = explode(':', $id);
        
        if ((count(explode(':', $id)) == 3) && (is_numeric($strExplode[1])) && (is_numeric($strExplode[2]))) {	
            $this->steamID = "STEAM_0:$strExplode[1]:$strExplode[2]";
            $this->steamID64 = bcadd((($strExplode[2] * 2) + $strExplode[1]), '76561197960265728');
		}
        
        elseif (is_numeric($id)) {
            $this->steamID64 = $id;
		}

        else {
            $this->customURL = urlencode($id);
		}
	}

    /**
	 *  Deletes all the old cach files that have not been updated in a while..
	 *       
	 * */
    function clearCacheFiles() {
        $cacheTime = max($this->gameCacheTime, $this->profileCacheTime) * 24;
        $cacheFile = "{$this->cacheDIR}/master.cache";
        
        if (!file_exists($cacheFile)) {
            @file_put_contents($cacheFile, @file_get_contents("http://www.google.com"));
            return;
        }    
       
        if (filemtime($cacheFile) + $cacheTime >= time()) {
            return; 
        }        
        
        $files = scandir($this->cacheDIR);
        
        foreach ($files as $i => $file) {
            if (end(explode('.', $file)) != 'cache') {
                continue;
            }
            
            $f = "{$this->cacheDIR}/{$file}";
            
            if ((substr($f, 0, 8) === 'profile_') && (filemtime($f) + $this->profileCacheTime >= time())) {                
                continue; 
            }

            if ((substr($f, 0, 6) === 'games_') && (filemtime($f) + $this->gamesCacheTime >= time())) {
                continue; 
            }
            
            @unlink($f);            
            
        }
        
        @file_put_contents($cacheFile, @file_get_contents("http://www.google.com"));
        
    }
    
    /**
	 *  Converts a valid steamID64 to steamID
	 *  @return str
	 * */
    function retrieveSteamID() {
        if ((empty($this->steamID64)) && (empty($this->steamID))) {
            $this->retrieveProfile();
        }

        if (!is_numeric($this->steamID64)) {
            return; 
        }

		if ((substr($this->steamID64, -1) % 2) == 0) {
            $server = 0;
        }
        
        else {
            $server = 1;
        }
		
        $auth = bcsub($this->steamID64, '76561197960265728');		
        $auth = bcsub($auth, $server);

        if (bccomp($auth, '0') != 1) {
            return;
        }

		$auth = bcdiv($auth, 2);
        
        $this->steamID = "STEAM_0:{$server}:{$auth}";
    }

	/**
	 *  Creates and then returns the url to the profiles.
	 *  @return string
	 * */
	function baseUrl() {
		if (empty($this->customURL)) {
			return "http://steamcommunity.com/profiles/{$this->steamID64}";
		}
		
        else {
			return "http://steamcommunity.com/id/{$this->customURL}";
		}
	}
	
	/**
	 *  Retrieves all of the games owned by the user
	 * */
	function retrieveGames() {		
        $cacheName = "{$this->cacheDIR}/games_{$this->steamID64}.cache"; 
        $url = $this->baseUrl() . '/games?xml=73'; // http://en.wikipedia.org/wiki/73_(number)   
		$gameData = new SimpleXMLElement(getCacheFile($url, $cacheName, $this->gameCacheTime));
		$this->gamesList = array();
		
        if (!empty($gameData->error)) {
			#throw new SteamAPIException((string) $gameData->error);
		}
		
		foreach($gameData->games->game as $game) {
			$g['appID'] = (string) $game->appID;
			$g['name']  = (string) $game->name;
			$g['logo'] = (string) $game->logo;
			$g['storeLink'] = (string) $game->storeLink;
			$g['hoursOnRecord'] = (float) $game->hoursOnRecord;
			$g['hoursLast2Weeks'] = (float) $game->hoursLast2Weeks;
			$this->gameList[] = $g;
			#print_r($this->gameList);
		}
	}

	/**
	 *  Retrieves the requested url, or a cached version of the url.
	 *  @ return string   
	 * */
    function getCacheFile($url, $cacheName, $cacheTime) {
        if (file_exists($cacheName) && (filemtime($cacheName) + $cacheTime >= time())) {
            return @file_get_contents($cacheName); 
        } 
        
        if (($this->customURL == '') && ($this->steamID64 == '')) {
            return @file_get_contents($url);
        }
        
        try {
            $contents = @file_get_contents($url);
            @file_put_contents($cacheName, $contents);    
        }
        
        catch (Exception $error) {
            @chmod($cacheDIR, 0766);
            
            if (!$contents) {
                $contents = @file_get_contents($url);
            }
            
            @file_put_contents($cacheName, $contents);                 
        }
        return $contents;     
    }

	/**
	 *  Retrieves all of the information found on the profile.
	 * */
	function retrieveProfile() {        
        if (empty($this->customURL)) {
            $cacheName = "{$this->cacheDIR}/profile_{$this->steamID64}.cache"; 
        }
        
        else {
            $cacheName = "{$this->cacheDIR}/profile_{$this->customURL}.cache"; 
        }
        
        $url = $this->baseUrl() . '?xml=73'; // http://en.wikipedia.org/wiki/73_(number)        
      
        $profileData = new SimpleXMLElement($this->getCacheFile($url, $cacheName, $this->profileCacheTime));       
        
		if (!empty($profileData->error)) {
			#throw new SteamAPIException((string) $profileData->error);
		}
		
		$this->steamID64 = (string) $profileData->steamID64;
		$this->friendlyName  = (string) $profileData->steamID;
	
		$this->onlineState = (string) $profileData->onlineState;
		$this->stateMessage = (string) $profileData->stateMessage;
		
		$this->privacyState = (string) $profileData->privacyState;
		$this->visibilityState = (int) $profileData->visibilityState;
		
		$this->avatarIcon = (string) $profileData->avatarIcon;
		$this->avatarMedium = (string) $profileData->avatarMedium;
		$this->avatarFull = (string) $profileData->avatarFull;
		
		$this->vacBanned = (int) $profileData->vacBanned;
	

		if ($this->privacyState == 'public') {
			$this->customUrl = strtolower((string) $profileData->customURL);
			
			$this->memberSince = (string) $profileData->memberSince;
			$this->steamRating = (float) $profileData->steamRating;
			$this->location = (string) $profileData->location;
			$this->realName = (string) $profileData->realname;
			
			$this->hoursPlayed2Wk = (float) $profileData->hoursPlayed2Wk;
			
			$this->favoriteGame = (string) $profileData->favoriteGame->name;
			$this->favoriteGameHoursPlayed2Wk = (string) $profileData->favoriteGame->hoursPlayed2wk;
			
			$this->headLine = (string) $profileData->headline;
			$this->summary = (string) $profileData->summary;
		}
		
		if (!empty($profileData->weblinks)) {
            foreach($profileData->weblinks->weblink as $link) {
                $this->weblinks[(string) $link->title] = (string) $link->link;
            }
        }

        $this->clearCacheFiles();
	}	

	/**
	 *  If there are no games in the variable it calls the retrieveGames() function, upon completion returns an array of all of the owned games and related information
	 *  @return array
	 * */
	function getGames() {
		if (empty($this->onlineState)) {
            $this->retrieveProfile();
        }
        
		if (empty($this->gameList)) {
			$this->retrieveGames();
		}

		return $this->gameList;
	}
	
	/**
	 *  Returns the friendly name of the user. The one seen by all friends & visitors.
	 *  @return string
	 * */
	function getFriendlyName() {
		if (empty($this->friendlyName)) {
            $this->retrieveProfile();
        }
        
        return $this->friendlyName;
	}
	
	/**
	 *  Returns the users current state. (online, offline)
	 *  @return string
	 * */
	function onlineState() {
		if (empty($this->onlineState)) {
            $this->retrieveProfile();
        }
        
        if ($this->onlineState == '') {
            return 'offline';
        }

        return $this->onlineState;
    }
    
	/**
	 *  Same as onlineState() except it returns proper case strings. (Online, Offline, In-Game)
	 *  @return string
	 * */
	function getOnlineState() {
		if (empty($this->onlineState)) {
            $this->retrieveProfile();
        }

        if ($this->onlineState() == 'in-game') {
            return 'In-Game';
        }
        
        if ($this->onlineState() == 'online') {
            return 'Online';
        }
        
        return 'Offline';
    }

    /**
	 *  Returns the state message of the user (EG: "Last Online: 2 hrs, 24 mins ago", "In Game <br /> Team Fortress 2")
	 *  @return string
	 * */
    function getStateMessage() {
		if (empty($this->stateMessage)) {
            $this->retrieveProfile();
        }

		return $this->stateMessage;
	}
    
    /**
	 *  Returns the short state message of the user (EG: "Last Online: 2 hrs, 24 mins ago", "Team Fortress 2", "Online")
	 *  @return string
	 * */
    function getShortStateMessage() {
		if (empty($this->onlineState)) {
            $this->retrieveProfile();
        }

		if ($this->stateMessage == '') {
            if ($this->onlineState == 'in-game') {
                return 'In-Game';
            }
            
            if ($this->onlineState == 'online') {
                return 'Online';
            }
            
            return 'Offline';
        }
        
        $details = explode('<br />', $this->stateMessage);
        
        if (isset($details[1])) {
            return $details[1];
        }
        
        return $details[0];
	}

    /**
	 *  Returns the users Vac status. 0 = Clear, 1 = Banned
	 *  @return int
	 * */
    function isBanned() {
		if (empty($this->vacBanned)) {
            $this->retrieveProfile();
        }
        
        return $this->vacBanned;
    }
    
    /**
	 *  Returns a link to the small sized avatar of the user (32x32)
	 *  @return string
	 * */
    function getAvatarSmall() {
		if (empty($this->avatarIcon)) {
            $this->retrieveProfile();
        }
        
		return $this->avatarIcon;
	}
	
	/**
	 *  Returns a link to the medium sized avatar of the user (64x64)
	 *  @return string
	 * */
	function getAvatarMedium() {
		if (empty($this->avatarMedium)) {
            $this->retrieveProfile();
        }
        
		return $this->avatarMedium;
	}
	
	/**
	 *  Returns a link to the full sized avatar of the user
	 *  @return string
	 * */
	function getAvatarFull() {
		if (empty($this->avatarLarge)) {
            $this->retrieveProfile();
        }
        
		return $this->avatarLarge;
	}
	
	/**
	 *  Returns the Steam ID of the user
	 *  @return int
	 * */
	function getSteamID64() {
		if (empty($this->steamID64)) {
            $this->retrieveProfile();
        }
        
		return $this->steamID64;
	}
	
	/**
	 *  Returns the total amount of games owned by the user
	 *  @return int
	 * */
	function getTotalGames() {
		if (empty($this->onlineState)) {
            $this->retrieveProfile();
        }
        
		return sizeof($this->getGames());
	}

	/**
	 *  Returns the steamID of the user
	 *  @return string
	 * */
	function getSteamID() {        
		if (empty($this->steamID)) {
			$this->retrievesteamID();
		}
		
        return $this->steamID;
	}
}

?>
